Skip to content

plans: restore free tier in Default() so api tests pass + email gate works#4

Merged
mastermanas805 merged 1 commit into
masterfrom
fix/plans-free-tier-2026-05-12
May 12, 2026
Merged

plans: restore free tier in Default() so api tests pass + email gate works#4
mastermanas805 merged 1 commit into
masterfrom
fix/plans-free-tier-2026-05-12

Conversation

@mastermanas805
Copy link
Copy Markdown
Member

Summary

The api repo's plans tests (TestDefault_AllStandardTiersPresent, TestAll_ReturnsAllPlans, TestFreeTier_MirrorsAnonymous) require a free tier in the common-module default registry. It was missing from defaultYAML in common/plans/plans.go (only anonymous, hobby, pro, team, growth). This PR restores free as a byte-for-byte mirror of anonymous.

Why free is real surface (not just test scaffolding)

  • api/internal/handlers/billing.go:361 sets tier = "free" for unpaid teams
  • api/internal/handlers/webhook.go:411-416 reaps both anonymous and free at 24h TTL
  • api/internal/handlers/openapi.go advertises "free" in 3 enum schemas
  • api/internal/models/resource_elevate_test.go:142 uses tier "free"
  • api/internal/handlers/onboarding_test.go:166 asserts tier == "free"
  • api/plans.yaml already defines a free block (lines 40-64), but Default() is hardcoded and ignores any yaml
  • FREE-TIER-RECYCLE-2026-05-12.md Option B (email gate) explicitly depends on free existing

Audience contract

Tier When TTL
anonymous pre-claim (no team_id) 24h
free claimed-but-unpaid (team_id set, no Razorpay sub) 24h

Pay-from-day-one policy holds: both get reaped at 24h. The two tiers must stay byte-identical so an anonymous -> free flip at claim time cannot widen or narrow quotas.

Test plan

  • common plans tests green (go test ./plans/... in common): 19 pass, 1 skip (file-consistency skipped — no plans.yaml in common repo)
  • api plans tests green (go test ./internal/plans/... in api with replace-directive): 17 pass (was 3 failing — now all 3 named tests green: TestDefault_AllStandardTiersPresent, TestAll_ReturnsAllPlans, TestFreeTier_MirrorsAnonymous)
  • api full unit test suite passes after this lands (verify locally before merging)
  • common plans_test.go updated to cover free in the default registry assertions

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

The api repo's plans tests (TestDefault_AllStandardTiersPresent,
TestAll_ReturnsAllPlans, TestFreeTier_MirrorsAnonymous) require a `free`
tier in the default registry. The api-level plans.yaml already defines
`free` as a byte-for-byte clone of `anonymous` (same limits, same
features) — the only difference being audience (free = claimed-but-unpaid
teams, anonymous = pre-claim agents). Both still get reaped at 24h, so
the pay-from-day-one policy holds.

The `free` tier is real product surface, not test scaffolding:
  - api/internal/handlers/billing.go:361 sets tier="free" for unpaid teams
  - api/internal/handlers/webhook.go:411-416 reaps both anonymous and free
  - api/internal/handlers/openapi.go advertises "free" in 3 schemas
  - api/internal/models/resource_elevate_test.go uses tier "free"
  - api/internal/handlers/onboarding_test.go asserts tier == "free"

The FREE-TIER-RECYCLE-2026-05-12.md plan also depends on `free` existing
in the registry (Option B email-gate falls into this tier).

Mirroring rule: anonymous and free must stay byte-identical so that an
anonymous->free flip at claim time cannot widen or narrow quotas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastermanas805 mastermanas805 merged commit 17e057d into master May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant